<?php
declare(strict_types=1);

namespace App\Controller\Admin;

use App\Agent\GameConfigAgent;
use App\Constants\ErrorCode;
use App\Constants\QmGame;
use App\Constants\RedisKey;
use App\Controller\InsideService\GameConfigInside;
use App\Middleware\AdminMiddleware;
use Hyperf\HttpServer\Annotation\Controller;
use Hyperf\HttpServer\Annotation\GetMapping;
use Hyperf\HttpServer\Annotation\Middleware;
use Hyperf\HttpServer\Annotation\PostMapping;
use Hyperf\Utils\ApplicationContext;
use Qcloud\Cos\Client;
use Vtiful\Kernel\Excel;

#[Controller(prefix: '/admin/GameConfig'), Middleware(AdminMiddleware::class)]
class GameConfigController extends BaseController {

    #[GetMapping(path: 'index')]
    public function index(): array {
        $userDataArr = $this->uInfo();
        $limit = $this->request->query('size', config('apiadmin.admin_list_default'));
        $page = $this->request->query('page', 1);
        $game_hash = $this->request->query('game_hash', '');
        $keywords = $this->request->query('keywords', '');

        if (empty($game_hash)) {
            $game_hash = $userDataArr['user_data']['bind_games'];
        }

        return (new GameConfigInside())->setCode($userDataArr['connection_code'])->index(
            $limit, $game_hash, $keywords, (int)$page
        );
    }

    #[PostMapping(path: 'edit')]
    public function edit(): array {
        $userDataArr = $this->uInfo();

        return (new GameConfigInside())->setCode($userDataArr['connection_code'])->edit($this->request->post());
    }

    #[PostMapping(path: 'confirmConf')]
    public function confirmConf(): array {
        $userDataArr = $this->uInfo();
        $unique = $this->request->post('unique', '');
        $id = $this->request->post('id', 0);
        $game_hash = $this->request->post('game_hash', '');

        $redis = (ApplicationContext::getContainer())->get(GameConfigAgent::class);
        if ($redis->exists(RedisKey::GM_CONF_TRANCE . ':' . $unique)) {
            $filePath = QmGame::CONFIG_JSON_PREFIX . $unique . '.json';

            file_put_contents(
                $filePath,
                $redis->get(RedisKey::GM_CONF_TRANCE . ':' . $unique)
            );
            $redis->del(RedisKey::GM_CONF_TRANCE . ':' . $unique);
            $this->uploadConfigToCos($filePath, $unique);
            (new GameConfigInside())->setCode($userDataArr['connection_code'])->confirmConf([
                'unique'    => $unique,
                'game_hash' => $game_hash,
                'id'        => $id
            ]);

            return $this->buildSuccess();
        }

        return $this->buildFailed(ErrorCode::NOT_EXISTS, '标识不存在');
    }

    /**
     * 将配置文件上传到COS
     * @param $path
     * @param $unique
     * @return void
     */
    private function uploadConfigToCos($path, $unique): void {
        $cosClient = new Client([
            'region'      => 'ap-shanghai',
            'schema'      => 'https',
            'credentials' => [
                'secretId'  => config('qcloud.secretId'),
                'secretKey' => config('qcloud.secretKey')
            ]
        ]);
        $cosClient->upload(
            'common-1302358887',
            '/sldnf/game_config_json/' . $unique . '.json',
            fopen($path, 'rb')
        );
    }

    #[PostMapping(path: 'importConf')]
    public function importConf(): array {
        if ($this->request->hasFile('file')) {
            $fileObj = $this->request->file('file');
            if ($fileObj->isValid()) {
                if ($fileObj->getExtension() === 'xlsx') {
                    $path = QmGame::CONFIG_JSON_PREFIX;
                    if (!file_exists($path) && !mkdir($path, 0755, true) && !is_dir($path)) {
                        throw new \RuntimeException(sprintf('Directory "%s" was not created', $path));
                    }
                    $new_name = md5(time() . uniqid('', true));
                    $fileObj->moveTo($path . $new_name);

                    if ($fileObj->isMoved()) {
                        $return = [];
                        $excel = (new Excel(['path' => $path]))->openFile($new_name)->openSheet()->setSkipRows(4);
                        $indexArr = $excel->nextRow();
                        while (($row = $excel->nextRow()) !== null) {
                            $rowItem = [];
                            foreach ($indexArr as $k => $v) {
                                $rowItem[$v] = empty($row[$k]) ? '' : $row[$k];
                            }
                            $return[] = $rowItem;
                        }
                        @unlink($path . $new_name);

                        $redis = (ApplicationContext::getContainer())->get(GameConfigAgent::class);
                        $redis->set(RedisKey::GM_CONF_TRANCE . ':' . $new_name, json_encode($return), 300);

                        return $this->buildSuccess([
                            'header' => $indexArr,
                            'data'   => $return,
                            'unique' => $new_name
                        ]);
                    }
                } else {
                    return $this->buildFailed(ErrorCode::FILE_SAVE_ERROR, '只能上传Excel文件');
                }
            } else {
                return $this->buildFailed(ErrorCode::FILE_SAVE_ERROR, '文件上传失败');
            }

            $error_message = match ($fileObj->getError()) {
                1 => '您上传的文件超过了PHP.INI配置文件中UPLOAD_MAX-FILESIZE的大小',
                2 => '您上传的文件超过了PHP.INI配置文件中的post_max_size的大小',
                3 => '文件只被部分上传',
                4 => '文件不能为空',
                default => '未知错误'
            };

            return $this->buildFailed(ErrorCode::FILE_SAVE_ERROR, $error_message);
        }

        return $this->buildFailed(ErrorCode::NOT_EXISTS, '未检测到文件');
    }

    /**
     * 新增配置删除
     * @return array
     * @throws \Exception
     */
    #[GetMapping(path: 'del')]
    public function del(): array {
        $id = $this->request->query('id');
        $game_hash = $this->request->query('game_hash');
        $userDataArr = $this->uInfo();

        return (new GameConfigInside())->setCode($userDataArr['connection_code'])->del($id, $game_hash);
    }

    #[PostMapping(path: 'add')]
    public function add(): array {
        $userDataArr = $this->uInfo();

        return (new GameConfigInside())->setCode($userDataArr['connection_code'])->add($this->request->post());
    }

    #[PostMapping(path: 'updateConf')]
    public function updateConf(): array {
        $game_hash_from = $this->request->post('game_hash_from', '');
        $game_hash_to = $this->request->post('game_hash_to', '');
        $userDataArr = $this->uInfo();

        return (new GameConfigInside())->setCode($userDataArr['connection_code'])->updateConf(
            $game_hash_from, $game_hash_to
        );
    }
}
